﻿using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace CPN.PJN.Silverlight.UI.Controls
{
    /// <summary>
    /// La WatermarkedTextBox affiche un certain visuel lorsque le contenu est vide
    /// </summary>
    [TemplatePart(Name = WatermarkTextBox.WatermarkContentControlName, Type = typeof(ContentControl))]
    [TemplateVisualState(Name = VisualStateHelper.StateNormal, GroupName = VisualStateHelper.GroupCommon)]
    [TemplateVisualState(Name = VisualStateHelper.StateMouseOver, GroupName = VisualStateHelper.GroupCommon)]
    [TemplateVisualState(Name = VisualStateHelper.StateDisabled, GroupName = VisualStateHelper.GroupCommon)]
    [TemplateVisualState(Name = VisualStateHelper.StateUnfocused, GroupName = VisualStateHelper.GroupFocus)]
    [TemplateVisualState(Name = VisualStateHelper.StateFocused, GroupName = VisualStateHelper.GroupFocus)]
    [TemplateVisualState(Name = WatermarkTextBox.StateUnwatermarked, GroupName = WatermarkTextBox.GroupWatermark)]
    [TemplateVisualState(Name = WatermarkTextBox.StateWatermarked, GroupName = WatermarkTextBox.GroupWatermark)]
    public class WatermarkTextBox : TextBox
    {
        #region Constants

        private const string WatermarkContentControlName = "WatermarkContentControl";

        private const string GroupWatermark = "WatermarkStates";
        private const string StateUnwatermarked = "Unwatermarked";
        private const string StateWatermarked = "Watermarked";

        #endregion

        private ContentControl elementContent;
        private bool isHovered;
        private bool hasFocus;

        #region Constructor

        /// <summary>
        /// Constructeur par défaut
        /// </summary>
        public WatermarkTextBox()
        {
            this.DefaultStyleKey = typeof(WatermarkTextBox);

            this.MouseEnter += OnMouseEnter;
            this.MouseLeave += OnMouseLeave;

            this.LostFocus += OnLostFocus;
            this.GotFocus += OnGotFocus;

            this.TextChanged += OnTextChanged;
        }

        #endregion

        /// <summary>
        /// Change pour le bon VisualState
        /// </summary>
        private void ChangeVisualState()
        {
            ChangeVisualState(true);
        }

        /// <summary>
        /// Change pour le bon VisualState
        /// </summary>
        /// <param name="useTransitions"> vrai pour utiliser les transitions, faux sinon
        /// </param>
        private void ChangeVisualState(bool useTransitions)
        {
            // CommonStates
            if (!IsEnabled)
            {
                VisualStateHelper.GoToState(this, useTransitions, VisualStateHelper.StateDisabled, VisualStateHelper.StateNormal);
            }
            else if (isHovered)
            {
                VisualStateHelper.GoToState(this, useTransitions, VisualStateHelper.StateMouseOver, VisualStateHelper.StateNormal);
            }
            else
            {
                VisualStateHelper.GoToState(this, useTransitions, VisualStateHelper.StateNormal);
            }

            // FocusStates
            if (hasFocus && IsEnabled)
            {
                VisualStateHelper.GoToState(this, useTransitions, VisualStateHelper.StateFocused, VisualStateHelper.StateUnfocused);
            }
            else
            {
                VisualStateHelper.GoToState(this, useTransitions, VisualStateHelper.StateUnfocused);
            }

            // WatermarkStates
            if (!hasFocus && this.Watermark != null && string.IsNullOrEmpty(this.Text))
            {
                VisualStateHelper.GoToState(this, useTransitions, StateWatermarked, StateUnwatermarked);
            }
            else
            {
                VisualStateHelper.GoToState(this, useTransitions, StateUnwatermarked);
            }
        }

        /// <summary>
        /// Applique le template
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            elementContent = GetTemplateChild(WatermarkContentControlName) as ContentControl;
            Debug.Assert(elementContent != null);

            OnWatermarkChanged();

            ChangeVisualState(false);
        }

        #region Watermark

        /// <summary>
        /// Watermark dependency property
        /// </summary>
        public new static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register(
            "Watermark", typeof(object), typeof(WatermarkTextBox), new PropertyMetadata(OnWatermarkPropertyChanged));

        /// <summary>
        /// Watermark
        /// </summary>
        public new object Watermark
        {
            get { return (object)GetValue(WatermarkProperty); }
            set { SetValue(WatermarkProperty, value); }
        }

        #endregion

        #region WatermarkContentTemplate

        /// <summary>
        /// WatermarkContentTemplate dependency property
        /// </summary>
        public static readonly DependencyProperty WatermarkContentTemplateProperty = DependencyProperty.Register(
            "WatermarkContentTemplate", typeof(ControlTemplate), typeof(WatermarkTextBox), null);

        /// <summary>
        /// WatermarkContentTemplate
        /// </summary>
        public ControlTemplate WatermarkContentTemplate
        {
            get { return (ControlTemplate)GetValue(WatermarkContentTemplateProperty); }
            set { SetValue(WatermarkContentTemplateProperty, value); }
        }

        #endregion

        #region WatermarkBrush

        /// <summary>
        /// WatermarkBrush dependency property
        /// </summary>
        public static readonly DependencyProperty WatermarkBrushProperty = DependencyProperty.Register(
            "WatermarkBrush", typeof(Brush), typeof(WatermarkTextBox), null);

        /// <summary>
        /// WatermarkBrush
        /// </summary>
        public Brush WatermarkBrush
        {
            get { return (Brush)GetValue(WatermarkBrushProperty); }
            set { SetValue(WatermarkBrushProperty, value); }
        }

        #endregion

        private void OnGotFocus(object sender, RoutedEventArgs e)
        {
            if (IsEnabled)
            {
                hasFocus = true;

                if (!string.IsNullOrEmpty(this.Text))
                {
                    Select(0, this.Text.Length);
                }

                ChangeVisualState();
            }
        }

        private void OnLostFocus(object sender, RoutedEventArgs e)
        {
            hasFocus = false;
            ChangeVisualState();
        }

        private void OnMouseEnter(object sender, MouseEventArgs e)
        {
            isHovered = true;

            if (!hasFocus)
            {
                ChangeVisualState();
            }
        }

        private void OnMouseLeave(object sender, MouseEventArgs e)
        {
            isHovered = false;

            ChangeVisualState();
        }

        private void OnTextChanged(object sender, TextChangedEventArgs e)
        {
            ChangeVisualState();
        }

        private void OnWatermarkChanged()
        {
            if (elementContent != null)
            {
                Control watermarkControl = this.Watermark as Control;
                if (watermarkControl != null)
                {
                    watermarkControl.IsTabStop = false;
                    watermarkControl.IsHitTestVisible = false;
                }
            }
        }

        /// <summary>
        /// Appelé quand le watermark change
        /// </summary>
        private static void OnWatermarkPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            WatermarkTextBox watermarkTextBox = sender as WatermarkTextBox;
            Debug.Assert(watermarkTextBox != null, "The source is not an instance of a WatermarkedTextBox !");

            watermarkTextBox.OnWatermarkChanged();
            watermarkTextBox.ChangeVisualState();
        }
    }
}